/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.collections.tuples;

import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.Locale;
import java.util.LinkedList;
import java.util.ArrayList;

import static com.softwarecraftsmen.collections.tuples.Quintuple.quintuple;
import static com.softwarecraftsmen.collections.tuples.Sextuple.sextuple;
import static com.softwarecraftsmen.collections.tuples.Septuple.septuple;

public class Quadruple<A, B, C, D> extends AbstractTuple
{
	@NotNull
	public final A a;
	@NotNull
	public final B b;
	@NotNull
	public final C c;
	@NotNull
	public final D d;

	private Quadruple(final @NotNull A a, final @NotNull B b, final @NotNull C c, final @NotNull D d)
	{
		super();
		this.a = a;
		this.b = b;
		this.c = c;
		this.d = d;
	}

	@NotNull
	public static <A, B, C, D> Quadruple<A, B, C, D> quadruple(@NotNull final A a, @NotNull final B b, final @NotNull C c, final @NotNull D d)
	{
		return new Quadruple<A, B, C, D>(a, b, c, d);
	}

	@NotNull
	public <E> Quintuple<A, B, C, D, E> append(@NotNull final E e)
	{
		return quintuple(a, b, c, d, e);
	}

	@NotNull
	public <E, F> Sextuple<A, B, C, D, E, F> append(@NotNull final E e, @NotNull final F f)
	{
		return sextuple(a, b, c, d, e, f);
	}

	@NotNull
	public <E, F, G> Septuple<A, B, C, D, E, F, G> append(@NotNull final E e, @NotNull final F f, @NotNull final G g)
	{
		return septuple(a, b, c, d, e, f, g);
	}

	@NotNull
	public Object valueAt(final Integer index)
	{
		guardValueAt(index);
		switch (index)
		{
			case 0:
				return a;
			case 1:
				return b;
			case 2:
				return c;
			case 3:
				return d;
			default:
				throw new IllegalStateException();
		}
	}


	@NotNull
	public ArrayList<Object> toLegacyArrayList()
	{
		return (ArrayList<Object>) addToList(super.toLegacyArrayList());
	}

	@NotNull
	public LinkedList<Object> toLegacyLinkedList()
	{
		return (LinkedList<Object>) addToList(super.toLegacyLinkedList());
	}

	private List<Object> addToList(final List<Object> list)
	{
		list.add(a);
		list.add(b);
		list.add(c);
		list.add(d);
		return list;
	}

	public int size()
	{
		return 4;
	}

	@NotNull
	public String toString()
	{
		return String.format(Locale.UK, "(%1$s, %2$s, %3$s, %4$s)", a, b, c, d);
	}

	public boolean equals(final Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final Quadruple quadruple = (Quadruple) o;

		if (!a.equals(quadruple.a))
		{
			return false;
		}
		if (!b.equals(quadruple.b))
		{
			return false;
		}
		if (!c.equals(quadruple.c))
		{
			return false;
		}
		if (!d.equals(quadruple.d))
		{
			return false;
		}

		return true;
	}

	public int hashCode()
	{
		int result;
		result = a.hashCode();
		result = 31 * result + b.hashCode();
		result = 31 * result + c.hashCode();
		result = 31 * result + d.hashCode();
		return result;
	}

	@NotNull
	public Triple<A, B, C> slice()
	{
		return tuple(a, b, c);
	}
}
